package patterns.behavioral.template;

/**
 * 模板方法模式示例
 * 定义一个操作中的算法骨架，将一些步骤延迟到子类中实现
 * 模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤
 */
public class TemplateMethodPattern {

    public static void main(String[] args) {
        // 数据挖掘示例
        System.out.println("===== 数据挖掘示例 =====");
        DataMiner csvMiner = new CSVDataMiner();
        csvMiner.mine("用户数据.csv");
        
        System.out.println();
        
        DataMiner databaseMiner = new DatabaseDataMiner();
        databaseMiner.mine("用户表");
        
        // 饮料制作示例
        System.out.println("\n===== 饮料制作示例 =====");
        Beverage coffee = new Coffee();
        coffee.prepareBeverage();
        
        System.out.println();
        
        Beverage tea = new Tea();
        tea.prepareBeverage();
        
        // 带钩子方法的示例
        System.out.println("\n===== 带钩子方法的示例 =====");
        Beverage coffeeWithoutCondiments = new Coffee();
        ((Coffee) coffeeWithoutCondiments).setWantsCondiments(false);
        coffeeWithoutCondiments.prepareBeverage();
    }
}

/**
 * 数据挖掘示例
 */
abstract class DataMiner {
    // 模板方法，定义算法骨架
    public final void mine(String path) {
        openFile(path);
        extractData();
        parseData();
        analyzeData();
        sendReport();
        closeFile();
    }
    
    // 具体方法，由父类实现
    protected void openFile(String path) {
        System.out.println("打开数据源: " + path);
    }
    
    // 抽象方法，由子类实现
    protected abstract void extractData();
    protected abstract void parseData();
    
    // 具体方法，由父类实现
    protected void analyzeData() {
        System.out.println("分析数据...");
    }
    
    protected void sendReport() {
        System.out.println("发送分析报告...");
    }
    
    protected void closeFile() {
        System.out.println("关闭数据源");
    }
}

class CSVDataMiner extends DataMiner {
    @Override
    protected void extractData() {
        System.out.println("从CSV文件中提取数据...");
    }
    
    @Override
    protected void parseData() {
        System.out.println("解析CSV数据...");
    }
}

class DatabaseDataMiner extends DataMiner {
    @Override
    protected void extractData() {
        System.out.println("从数据库中提取数据...");
    }
    
    @Override
    protected void parseData() {
        System.out.println("解析数据库记录...");
    }
    
    // 重写父类的具体方法
    @Override
    protected void closeFile() {
        System.out.println("关闭数据库连接");
    }
}

/**
 * 饮料制作示例（带钩子方法）
 */
abstract class Beverage {
    // 模板方法
    public final void prepareBeverage() {
        boilWater();
        brew();
        pourInCup();
        if (customerWantsCondiments()) {
            addCondiments();
        }
        System.out.println("饮料制作完成！");
    }
    
    // 具体方法
    private void boilWater() {
        System.out.println("将水煮沸");
    }
    
    // 抽象方法
    protected abstract void brew();
    protected abstract void addCondiments();
    
    // 具体方法
    private void pourInCup() {
        System.out.println("倒入杯中");
    }
    
    // 钩子方法，子类可以覆盖
    protected boolean customerWantsCondiments() {
        return true; // 默认返回true
    }
}

class Coffee extends Beverage {
    private boolean wantsCondiments = true;
    
    public void setWantsCondiments(boolean wantsCondiments) {
        this.wantsCondiments = wantsCondiments;
    }
    
    @Override
    protected void brew() {
        System.out.println("用沸水冲泡咖啡");
    }
    
    @Override
    protected void addCondiments() {
        System.out.println("加入糖和牛奶");
    }
    
    // 覆盖钩子方法
    @Override
    protected boolean customerWantsCondiments() {
        return wantsCondiments;
    }
}

class Tea extends Beverage {
    @Override
    protected void brew() {
        System.out.println("用沸水浸泡茶叶");
    }
    
    @Override
    protected void addCondiments() {
        System.out.println("加入柠檬");
    }
} 